<script setup>
import {ref, reactive, onMounted, computed, nextTick} from 'vue'
import {httpKnowledgeList, httpFiles, httpSave, httpUploadFiles, httpDeleteFiles, httpDelete} from '@/api/knowledge.js'
import Pagination from '@/components/pagination/index.vue'
import useKnowledgeStore from '@/stores/knowledge.js'
import {useRouter} from 'vue-router'
import {formatFileSize} from '@/utils/index.js'
import ImageShow from '@/components/image-show/index.vue'
import {ElMessageBox, ElMessage} from 'element-plus'
import DocumentViewer from '@/components/document-viewer/index.vue'
const knowledgeStore = useKnowledgeStore()
const router = useRouter()
const imagePrefix = import.meta.env.VITE_IMAGE_SUFFIX

onMounted(() => {
  init()
  setMainHeight()
})
const loading = ref(false)
const knowledgeList = ref([])
const knowledgeTotal = ref(0)
const query = reactive({
  sort_id: 0,
  page: 1,
  keyword: '',
  limit: 20,
  is_private: 1
})

const submitForm = ref(null)
const default_detail = {
  id: 0,
  knowledge_id: 0,
  name: '',
  description: '',
  avatar: undefined
}

const rules = {
  name: [{required: true, message: '此项为必填项。', trigger: 'blur'}],
  description: [{required: true, message: '此项为必填项。', trigger: 'blur'}]
}
const avatars = computed(() => {
  return detail.avatar ? [detail.avatar] : []
})
const detail = reactive({...default_detail})
const detailShow = ref(false)

const handleAdd = async (formEl) => {
  for (let key in default_detail) {
    detail[key] = default_detail[key]
  }
  detailShow.value = true
  await nextTick()
  formEl.clearValidate && formEl.clearValidate()
}

const handleUpdate = async (formEl, row) => {
  for (let key in row) {
    if (Object.keys(default_detail).indexOf(key) > -1) {
      detail[key] = row[key]
    }
  }
  detail.knowledge_id = row.id
  detailShow.value = true
  await nextTick()
  formEl.clearValidate && formEl.clearValidate()
}

const useKnowledge = (item) => {
  if (knowledgeStore.getKnowledge().id === item.id) {
    knowledgeStore.setKnowledge(0, '')
  } else {
    knowledgeStore.setKnowledge(item.id, item.name)
    router.push('/chat?add=1')
  }
}

const allAvatars = computed(() => {
  return knowledgeList.value.map(item => {
    return imagePrefix + item.avatar
  })
})

const init = async () => {
  loading.value = true
  await getList(false)
  loading.value = false
}

const getList = async (showLoading = true) => {
  if (showLoading) loading.value = true
  const response = await httpKnowledgeList({...query}).catch(() => null)
  if (showLoading) loading.value = false
  if (!response) return
  const {list, total} = response
  knowledgeList.value = list
  knowledgeTotal.value = total
}

const files = ref([])
const fileTotal = ref(0)
const list_loading = ref(false)
const fileShow = ref(false)
const knowledgeName = ref('')
const params = reactive({
  knowledge_id: 0,
  keyword: '',
  page: 1,
  limit: 20
})

const showFiles = (id, kn) => {
  params.knowledge_id = id
  params.keyword = ''
  params.limit = 20
  params.page = 1
  files.value = []
  fileShow.value = true
  knowledgeName.value = kn
  getFiles()
}

const changeCategory = () => {
  params.page = 1
  getList()
}

let timer = null

const loopGetList = () => {
  let loop = false
  files.value.forEach(item => {
    const {status} = item
    if (status === 1) {
      loop = true
    }
  })
  if (loop) {
    timer = setTimeout(() => {
      getFiles(true)
    }, 10000)
  }
}

const handleFileFilter = () => {
  params.page = 1
  getFiles()
}

const getFiles = async (loop = false) => {
  if (timer) {
    clearTimeout(timer)
  }
  if (!loop) list_loading.value = true
  const response = await httpFiles({...params}).catch(() => null)
  if (!loop) list_loading.value = false
  if (!response) {
    return
  }
  const {list, count} = response
  files.value = list
  fileTotal.value = count
  loopGetList()
}

const mainHeight = ref(document.body.clientHeight)

const setMainHeight = () => {
  window.onresize = () => {
    mainHeight.value = document.body.clientHeight
  }
}

const handleDelete = async (id) => {
  const confirm = await ElMessageBox.confirm('确认删除此资料库，删除后无法恢复？', '确认消息').then(() => true).catch(() => false)
  if (!confirm) return
  loading.value = true
  const response = await httpDelete(id).then(() => true).catch(() => false)
  if (response) {
    await getList()
  } else {
    loading.value = false
  }
}

const handleSubmit = async (formEl) => {
  const validate = await formEl.validate(valid => valid)
  if (!validate) return
  list_loading.value = true
  const data = {...detail}
  if (data.avatar === "") {
    data.avatar = undefined
  }
  const response = await httpSave(data).then(() => true).catch(() => false)
  if (response) {
    detailShow.value = false
    await getList()
  } else {
    list_loading.value = false
  }
}

const uploadSuccess = (file_id) => {
  detail.avatar = file_id
}

const deleteImage = () => {
  detail.avatar = undefined
}

const selected = ref([])
const uploadShow = ref(false)
const uploadFiles = ref([])
const uploadFilesRef = ref(null)
const accept = ['.pdf', '.docx', '.xlsx', '.pptx', '.png', '.jpg', '.jpeg', '.txt', '.html', '.md', '.json', '.csv', '.xml', '.log', '.py']
const filenames = computed(() => {
  return selected.value.map(item => {
    const {file_name} = item
    return file_name
  })
})

const handleSelectionChange = (v) => {
  selected.value = v
}

const handleDeleteFiles = async (row = null) => {
  if (row) {
    handleSelectionChange([row])
    await nextTick()
  } else {
    if (!filenames.value.length) {
      ElMessage.warning('请选择要删除的项')
    }
  }
  const confirm = await ElMessageBox.confirm('删除后无法恢复，确认删除选中文件？', '确认提示', {
    confirmButtonText: '确认删除',
    cancelButtonText: '再想想'
  }).then(() => true).catch(() => false)
  if (!confirm) return
  list_loading.value = true
  const response = await httpDeleteFiles({
    knowledge_id: params.knowledge_id,
    file_names: filenames.value
  }).catch(() => null)
  list_loading.value = false
  if (!response) return
  const {failed_files} = response
  if (failed_files.length > 0) {
    await ElMessageBox.alert(failed_files.join("<br />"), "提示", {
      dangerouslyUseHTMLString: true
    })
  } else {
    ElMessage.success('删除成功')
  }
  if (failed_files.length !== filenames.value.length) {
    await getFiles()
  }
}

const handleShowUpload = async (uploadEl) => {
  uploadShow.value = true
  await nextTick()
  uploadEl.clearFiles && uploadEl.clearFiles()
}

const uploadOnExceed = () => {
  ElMessage.warning('单次最多可上传6个文件')
}

const handleBeforeUpload = (file) => {
  uploadFiles.value.push(file)
  return false
}

const getFileExt = (filename) => {
  const name_arr = filename.split('.')
  if (name_arr.length <= 1) {
    return '._'
  } else {
    return '.' + name_arr[name_arr.length - 1]
  }
}

const handleOnChange = (uploadEl, file) => {
  if (file.size > 50 * 1024 * 1024) {
    ElMessage.warning('单个文件不能超过50M')
    uploadEl.handleRemove(file)
    return false
  }
  if (!accept.includes(getFileExt(file.name))) {
    ElMessage.warning('不支持的文件格式：' + file.name)
    uploadEl.handleRemove(file)
    return false
  }
}

const handleOnError = (uploadEl) => {
  uploadEl.clearFiles && uploadEl.clearFiles()
}

const handleUpload = async (uploadEl) => {
  uploadEl.submit()
  await nextTick()
  if (!uploadFiles.value.length) return
  const form = new FormData()
  form.append('knowledge_id', params.knowledge_id)
  uploadFiles.value.forEach(file => {
    form.append('files', file)
  })
  uploadEl.clearFiles()
  list_loading.value = true
  const response = await httpUploadFiles(form).catch(() => null)
  list_loading.value = false
  if (!response) return
  const {failed_files} = response
  if (failed_files.length) {
    await ElMessageBox.alert(failed_files.join("<br />"), "提示", {
      dangerouslyUseHTMLString: true
    })
  } else {
    ElMessage.success('文件上传成功')
    uploadShow.value = false
  }
  if (failed_files.length !== uploadFiles.value.length) {
    await getFiles()
  }
  uploadFiles.value = []
}

const showFileEnable = ref(false)
const showFileUrl = ref('')
const showFileName = ref('')
const showFileExt = ref('')

const downloadFile = (item, preview = false) => {
  const host = import.meta.env.VITE_BASE_API
  const url = host + `/knowledge/download-docs?knowledge_id=${params.knowledge_id}&file_name=${item.file_name}&preview=${preview ? 1 : 0}`
  if (!preview) {
    window.open(url)
  } else {
    showFileExt.value = getFileExt(item.file_name)
    showFileName.value = item.file_name
    showFileUrl.value = url
    showFileEnable.value = true
  }
}

</script>

<template>
  <div class="pw-100 vh-100 knowledge-bg knowledge-mem">
    <div>
      <el-input
          prefix-icon="Search"
          v-model="query.keyword"
          @keyup.native.enter="changeCategory"
          maxlength="32"
          clearable
          placeholder="搜索个人资料库"
          class="w-300 margin-left-10"
      />
      <el-button class="margin-left-10" icon="Search" type="primary" @click="changeCategory">搜索</el-button>
      <el-button class="margin-left-10" icon="CirclePlus" type="warning" @click="handleAdd">新增</el-button>
    </div>
    <div v-loading="loading" class="padding-10 knowledge-box">
      <el-row :gutter="20" v-if="knowledgeList.length">
        <el-col
            v-for="(item, index) in knowledgeList"
            :key="index"
            :xs="12"
            :sm="12"
            :md="8"
            :lg="8"
            :xl="6"
        >
          <div class="flex justify-content-center item-kno border-radius margin-bottom-20 padding-15">
            <div class="w-50 text-center">
              <el-image
                  fit="cover"
                  :src="imagePrefix + item.avatar"
                  :preview-src-list="allAvatars"
                  :initial-index="index"
                  class="w-50 h-50"
              />
              <el-button
                  size="small"
                  :type="knowledgeStore.getKnowledge().id === item.id ? 'danger' : 'primary'"
                  plain
                  @click="useKnowledge(item)"
              >
                {{ knowledgeStore.getKnowledge().id === item.id ? '取消' : '使用' }}
              </el-button>
            </div>
            <div class="knowledge-info pointer" @click="showFiles(item.id, item.name)">
              <div class="text-ellipsis title" :title="item.name">
                <el-text class="font-size-2xl font-bold">{{ item.name }}</el-text>
              </div>
              <el-tooltip
                  effect="dark"
              >
                <template #content>
                  <div style="max-width: 400px">{{ item.description }}</div>
                </template>
                <div class="description flex align-items-center">
                  <div class="desc-b">
                    <el-text>{{ item.description }}</el-text>
                  </div>
                </div>
              </el-tooltip>
            </div>
            <div
                class="collection delete"
                @click="handleDelete(item.id)"
            >
              <el-icon>
                <component is="Delete"></component>
              </el-icon>
            </div>
            <div
                class="collection"
                @click="handleUpdate(submitForm, item)"
            >
              <el-icon>
                <component is="Edit"></component>
              </el-icon>
            </div>
          </div>
        </el-col>
      </el-row>
      <el-empty description="暂无个人资料库" v-else/>
      <pagination
          :total="knowledgeTotal"
          v-model:page="query.page"
          v-model:limit="query.limit"
          @pagination="getList"
      />
    </div>
  </div>
  <el-dialog
      v-model="fileShow"
      width="80vw"
      top="5vh"
      :close-on-click-modal="false"
      :title="`《${knowledgeName}》文件列表`"
      center
  >
    <div class="margin-bottom-20">
      <el-input
          class="w-300"
          placeholder="搜索文件名称"
          clearable
          maxlength="100"
          v-model="params.keyword"
          @keyup.native.enter="handleFileFilter"
      />
      <el-button
          class="margin-left-10"
          type="primary"
          icon="Search"
          @click="handleFileFilter"
          :loading="list_loading"
      >搜索
      </el-button>
      <el-button
          type="warning"
          icon="UploadFilled"
          :loading="loading"
          @click="handleShowUpload(uploadFilesRef)"
      >上传文件
      </el-button>
      <el-button
          type="danger"
          icon="Delete"
          @click="handleDeleteFiles(null)"
          :disabled="selected.length === 0"
          :loading="loading"
      >批量删除
      </el-button>
    </div>
    <el-table
        class="header-lighter"
        :data="files"
        stripe
        border
        :max-height="mainHeight - 270"
        highlight-current-row
        show-overflow-tooltip
        fit
        v-loading="list_loading"
        @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="40"/>
      <el-table-column
          width="60"
          label="序号"
      >
        <template #default="{$index}">
          <span>{{ $index + 1 }}</span>
        </template>
      </el-table-column>
      <el-table-column
          label="文件名"
          min-width="300"
          prop="file_name"
      />
      <el-table-column
          label="文件大小"
          min-width="120"
      >
        <template #default="scope">
          <span>{{ formatFileSize(scope.row.file_size) }}</span>
        </template>
      </el-table-column>
      <el-table-column
          label="状态"
          min-width="100"
      >
        <template #default="scope">
          <el-tag type="warning" v-if="scope.row.status === 1">处理中</el-tag>
          <el-tag type="success" v-if="scope.row.status === 2">已完成</el-tag>
          <el-tag type="danger" v-if="scope.row.status === 3">处理失败</el-tag>
        </template>
      </el-table-column>
      <el-table-column
          label="失败原因"
          min-width="100"
      >
        <template #default="scope">
          <span v-if="scope.row.status === 3">
            {{ scope.row.reason }}
          </span>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" width="180">
        <template #default="scope">{{ scope.row.created_at.replace('T', ' ') }}</template>
      </el-table-column>
      <el-table-column label="操作" width="240" fixed="right">
        <template #default="scope">
          <el-button
              type="primary"
              icon="Download"
              link
              @click="downloadFile(scope.row)"
              :loading="loading"
          >下载
          </el-button>
          <el-button
              type="primary"
              icon="View"
              link
              @click="downloadFile(scope.row, true)"
              :loading="loading"
          >预览
          </el-button>
          <el-button
              type="danger"
              icon="Delete"
              link
              @click="handleDeleteFiles(scope.row)"
              :loading="loading"
          >删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination
        :total="fileTotal"
        v-model:limit="params.limit"
        v-model:page="params.page"
        @pagination="getFiles"
    />
    <el-dialog
        v-model="uploadShow"
        append-to-body
        draggable
        width="700"
        top="10vh"
        :close-on-click-modal="false"
        title="上传文件"
        center
    >
      <el-upload
          ref="uploadFilesRef"
          name="files"
          drag
          multiple
          :on-exceed="uploadOnExceed"
          :auto-upload="false"
          :limit="6"
          :accept="accept.join(',')"
          :before-upload="handleBeforeUpload"
          :on-error="() => handleOnError(uploadFilesRef)"
          :on-change="(file) => handleOnChange(uploadFilesRef, file)"
      >
        <el-icon class="el-icon--upload">
          <component is="UploadFilled"/>
        </el-icon>
        <div class="el-upload__text">
          拖动文件到此处或者<em>点击上传</em>支持文件格式：<br/>{{ accept.join('，') }}
        </div>
      </el-upload>
      <template #footer>
        <el-button type="primary" @click="handleUpload(uploadFilesRef)" :loading="loading">确认上传</el-button>
        <el-button type="warning" @click="uploadShow=false" :loading="loading">取 消</el-button>
      </template>
    </el-dialog>
  </el-dialog>
  <el-dialog
      v-model="detailShow"
      :close-on-click-modal="false"
      :title="`${detail.id ? '编辑' : '新增'}知识库`"
      width="650px"
      top="10vh"
      draggable
      center
  >
    <el-form label-width="200" :rules="rules" :model="detail" ref="submitForm">
      <el-form-item
          label="知识库名称："
          prop="name"
      >
        <el-input
            :disabled="detail.id > 0"
            v-model="detail.name"
            maxlength="30"
            class="w-300"
            clearable
            placeholder="输入知识库名称"
        />
      </el-form-item>
      <el-form-item
          label="知识库简介："
          prop="description"
      >
        <el-input
            v-model="detail.description" maxlength="250" class="w-300" clearable placeholder="输入知识库简介"
            type="textarea" :rows="4" resize="none" show-word-limit
        />
      </el-form-item>
      <el-form-item
          label="知识库图片："
          prop="avatar"
      >
        <image-show
            :list="avatars"
            :limit="1"
            :show-drag="false"
            :on-success="uploadSuccess"
            :on-delete="deleteImage"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button type="primary" @click="handleSubmit(submitForm)" :loading="list_loading">提 交</el-button>
      <el-button type="warning" @click="detailShow=false" :loading="list_loading">取 消</el-button>
    </template>
  </el-dialog>
  <document-viewer :file-name="showFileName" :ext="showFileExt" v-model:show="showFileEnable" :url="showFileUrl"/>
</template>

<style scoped lang="scss">
.knowledge-bg {
  background-color: var(--el-bg-color);
  position: absolute;
  left: 0;
  top: 0;
  padding: 20px;
}

.item-kno {
  background: var(--el-bg-color);
  transition: color 0.2s, background-color 0.2s;
  box-shadow: 0 0 6px rgba(0, 0, 0, 0.24);
  position: relative;
}

.dark {
  .item-kno {
    background: var(--el-color-info-light-9);
    box-shadow: var(--el-box-shadow-lighter);
  }
}

.knowledge-box {
  margin-top: 10px;
  overflow-y: auto;
  overflow-x: hidden;
  height: calc(100vh - 75px);
}

.knowledge-mem {

  .knowledge-info {
    width: calc(100% - 50px);
    padding-left: 12px;

    .description {
      height: 50px;
      overflow: hidden;
      .desc-b {
        max-height: 48px;
        display: -webkit-box;
        overflow: hidden;
        text-overflow: ellipsis;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
      }
    }

    .title {
      width: calc(100% - 60px);
    }
  }

  .collection {
    width: 20px;
    height: 20px;
    position: absolute;
    right: 30px;
    top: 10px;
    font-size: 16px;
    cursor: pointer;
    color: var(--el-color-primary);

    &.delete {
      color: var(--el-color-danger);
      right: 8px;

      i {
        top: -1px;
      }
    }
  }
}
</style>